/******************************************************************************
*	main.s
*	 by Alex Chadwick
*
*	A sample assembly code implementation of the screen01 operating system, that 
*	creates a frame buffer and continually renders to it.
*
*	main.s contains the main operating system, and IVT code.
******************************************************************************/

/* Modified by Romuald Sifflet and Nathalie Möller */
.section .rodata
.align 2
	.equ IMG_WIDTH, 400
	@.equ IMG_WIDTH, 1024
	.equ IMG_HEIGHT, 400
	@.equ IMG_HEIGHT, 768
	.equ SCALEPARAM, 10
	.equ RE_MIN, 0xfffffa00 @ -1.5 *1024
	.equ RE_MAX, 0x4cc @ 1.2 * 1024
	.equ IM_MIN, 0
	.equ IM_MAX, 0x600 @ 1.5 * 1024
	.equ WFACT, (RE_MAX - RE_MIN)/(IMG_WIDTH-1)
	.equ HFACT, (IM_MAX - IM_MIN)/(IMG_HEIGHT-1)

/*
* .globl is a directive to our assembler, that tells it to export this symbol
* to the elf file. Convention dictates that the symbol _start is used for the 
* entry point, so this all has the net effect of setting the entry point here.
* Ultimately, this is useless as the elf itself is not used in the final 
* result, and so the entry point really doesn't matter, but it aids clarity,
* allows simulators to run the elf, and also stops us getting a linker warning
* about having no entry point. 
*/
.section .init
.globl _start
_start:

/*
* Branch to the actual main code.
*/
b main

/*
* This command tells the assembler to put this code with the rest.
*/
.section .text

/*
* main is what we shall call our main operating system method. It never 
* returns, and takes no parameters.
* C++ Signature: void main(void)
*/
main:

/*
* Set the stack point to 0x8000.
*/
	mov sp,#0x8000

/* NEW
* Setup the screen.
*/
	ldr r0, =IMG_WIDTH
	ldr r1, =IMG_HEIGHT
	mov r2,#24
	bl InitialiseFrameBuffer

/* NEW
* Check for a failed frame buffer.
*/
	teq r0,#0
	bne noError$
		
	mov r0,#16
	mov r1,#1
	bl SetGpioFunction

	mov r0,#16
	mov r1,#0
	bl SetGpio

	error$:
		b error$

	noError$:

	fbInfoAddr .req r4
	mov fbInfoAddr,r0

/* NEW
* Set pixels forevermore. 
*/
render$:
	fbAddr .req r5
	ldr fbAddr,[fbInfoAddr,#32]
	w .req r6
	ldr w, =IMG_WIDTH

/* NEW
* We will use r0 to keep track of the current colour.
*/
	re .req r0
	im .req r1
	p .req r2
	y .req r7
	ldr p, =SCALEPARAM
	ldr y, =IMG_HEIGHT
	sub y, #1
	drawRow$:
		x .req r8
		mov x, #0
		drawPixel$:
			@ Compute Real part of c
			ldr r9, =WFACT
			mul re, x, r9
			ldr r10, =RE_MIN
			add re, re, r10
			@ Compute Imaginary part of c
			ldr r9, =HFACT
			mul im, y, r9
			ldr r10, =IM_MIN
			add im, im, r10

			@ Check convergence speed
			bl iteration
		
			@ Fill fb
			strb r0,[fbAddr]
			strb r0,[fbAddr, #1]
			strb r0,[fbAddr, #2]
			add fbAddr,#3
			add x, #1
			teq x, w
			bne drawPixel$

		sub y,#1
		tst y,#0
		bge drawRow$

	b render$

	.unreq fbAddr
	.unreq fbInfoAddr
	.unreq w

iteration:
	/* sauvegarde sur la pile */
	stmfd sp!, {r4-r11, lr}		

initialize:
	/* zRe = 0, zIm = 0, k=0*/
	mov r3, #0
	mov r4, #0
	mov r5, #0
	/* r11 = shift -1 */
	sub r11, r2, #1
									
test1:
	/*  zRe^2 / s  */
	mul r6, r3, r3
	LSR r6, r6, r2
	
	/*  zIm^2 / s  */
	mul r7, r4, r4
	LSR r7, r7, r2	

	/* zRe^2 / s  +  zIM^2 / s */
	add r8, r6, r7
								
	/* 4 x s */
	mov r9, #4
	LSL r9, r9, r2
	
	/* (zRe*zRe/s + zIm*zIm/s <= 4*s) */
	cmp r8, r9
	bgt end_iter

test2:
	/* k < 255 */
	cmp r5, #255
	bge end_iter

loop:
	/* zReOld = zRe */
	mov r10, r3
					
	/* zRe = zRe*zRe/s - zIm*zIm/s + cRe */
	sub r3, r6, r7
	add r3, r3, r0
										
	/* zIm = 2*zIm*zReOld/s + cIm */
	mul r6, r4, r10
	ASR r4, r6, r11
	add r4, r4, r1

	/* k += 1 */
	add r5, #1
	b test1
																			
end_iter:
	/* valeur de retour, return k */
	mov r0, r5

	/* restaure la pile */
	ldmfd sp!, {r4-r11, lr}
	bx lr

